#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>



void usage(){

	fprintf(stderr,
		"Usage : wepcrack [-h] [-l KEY-LEN]\n"
	 	"Options et arguments :\n"
		 "		-h		affiche uniquement ce message d'aide\n"
		 "		-l KEY-LEN	 cherche une clé de taille KEY-LEN bits "
		 "(40 ou 104 uniquement)\n");
}

void
swap(int* i, int* j){

	int tmp = *j;
	*j = *i;
	*i = tmp;
}

int main(int argc, char **argv){

	uint8_t buf[6], len = 40;
	int S[256], K[16], vote[256], m=3, i=0, j=0, np=0, res=0, ivs[100][3];
	int max=0, maxi=0,total=0;

	for(i=0; i<100; i++)
		ivs[i][0] = ivs[i][1] = ivs[i][2] = 0; 

	for(i=0; i<256; i++) vote[i] = 0;
	for(i=0; i<16; i++) K[i] = 0;

	for (--argc, ++argv; argc; --argc, ++argv) {
		if (!strcmp(*argv, "-h")) {
			usage();
			return EXIT_SUCCESS;
		}
		else if (!strcmp(*argv, "-l")) {
			char *ptr;
			--argc;
			len = strtol(*++argv, &ptr, 10);
			if (*ptr || (len != 40 && len != 104)) {
				fprintf(stderr, "Taille de clé invalide : `%s'.\n", *argv);
				usage();
				return EXIT_FAILURE;
			}
		}
		else {
			fprintf(stderr, "Option non supportée : `%s'.\n", *argv);
			usage();
			return EXIT_FAILURE;
		}
	}

	len >>= 3;

	while (fread(buf, 1, 6, stdin)) {

		total++;

		res = 1;

		for(i=0; i<np; i++)
			if(ivs[i][0] == buf[0] && ivs[i][1] == buf[1] && ivs[i][2] == buf[2]){
				res = 0;
				break;
			}

		if(!res) continue;		

	 	K[0] = buf[0];
	 	K[1] = buf[1];
		K[2] = buf[2];

 
		for(i=0; i<256; i++) S[i]=i;

		for(i=0, j=0; i<m; i++){

			j = (j + K[i] + S[i]) & 0xff; /* & 0xFF <=> % 256*/
			swap(S+i, S+j);
		}

		/* A_s5_1 */
		if((S[1] < m) && ((S[1] + S[S[1]]) == m)){

			for(i=0; S[i]!=(buf[3]^0xaa); i++); /* R[0] = C[0] XOR 0xAA */
			vote[(i-j-S[m]) & 0xff]++;
			np++;
		}

		/* A_s13 */
		if((S[1] == m) && ((buf[3]^0xaa) == m)){

			for(i=0; S[i]!=(buf[3]^0xaa); i++);
			vote[(i-j-S[m]) & 0xff]++;
			np++;
		}
		
		/* A_w13_1 */
		if((S[1] == m) && ((buf[3]^0xaa) == ((1-m) & 0xff))){

			for(i=0; S[i]!=(buf[3]^0xaa); i++);
			vote[(i-j-S[m]) & 0xff]++;
			np++;
		}

		/* A_w13_3 */
		if((S[m] == m) && ((buf[3]^0xaa) == S[1]) && (S[1] == ((1-m) & 0xff))){

			vote[(1-S[m]-j) & 0xff]++;
			np++;
		}

		/* A_4_s13 */
		for(i=0; S[i]!=(buf[4]^0xaa); i++);
		if((S[1]>m) && (((S[2]+S[1]) & 0xff) == m) && ((buf[4]^0xaa) == ((2-S[2]) & 0xff)) && i!=1 && i!=2){

			vote[(i-S[m]-j) & 0xff]++;
			np++;
		}

		/* A_neg */
		if((S[1] == 2) && (S[2] == 0) && ((buf[3]^0xaa) == 2)){

			vote[(1-j-S[m]) & 0xff] = -100;
			vote[(2-j-S[m]) & 0xff] = -100;
			np++;
		}

		if(np >= 100){

			for(max=0, maxi=0, i=0; i<256; i++)
				if(vote[i]>max){max = vote[i]; maxi = i;}
			K[m] = maxi;
			
			m++;

			printf("%d ieme octet trouvé : %02x\n",m-3,maxi);

			np = 0;
		
			for(i=0; i<256; i++) vote[i] = 0;

			for(i=0; i<100; i++)
				ivs[i][0] = ivs[i][1] = ivs[i][2] = 0; 
		
			if(m>=(len+3)) goto finish;
		}
	}

finish:
	
	printf("*** KWEP ***\n");
	for(i=3; i<(len+3); i++)
		printf("%02x ", K[i]);
	printf("\n%d paquets traités\n",total);

	return EXIT_SUCCESS;
}
